package com.ruoyi.common.utils.sql;

import com.ruoyi.common.exception.UtilException;
import com.ruoyi.common.utils.StringUtils;

/**
 * sql操作工具类
 *
 * @author ruoyi
 */
public class SqlUtil {
    /**
     * 定义常用的 sql关键字
     */
    public static String SQL_REGEX = "\u000B|and |extractvalue|updatexml|sleep|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |union |like |+|/*|user()";

    /**
     * 仅支持字母、数字、下划线、空格、逗号、小数点（支持多个字段排序）
     */
    public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+";

    /**
     * 限制orderBy最大长度
     */
    private static final int ORDER_BY_MAX_LENGTH = 500;

    /**
     * 检查字符，防止注入绕过
     *
     * @param value 待检查的排序字段字符串
     * @return 返回原始值，如果校验通过
     * @throws UtilException 当参数不符合规范或超过长度限制时抛出异常
     */
    public static String escapeOrderBySql(String value) {
        // 校验排序字段是否合法
        if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value)) {
            throw new UtilException("参数不符合规范，不能进行查询");
        }
        // 校验排序字段长度是否超限
        if (StringUtils.length(value) > ORDER_BY_MAX_LENGTH) {
            throw new UtilException("参数已超过最大限制，不能进行查询");
        }
        return value;
    }

    /**
     * 验证 order by 语法是否符合规范
     *
     * @param value 待验证的排序字段字符串
     * @return 合法返回true，否则返回false
     */
    public static boolean isValidOrderBySql(String value) {
        return value.matches(SQL_PATTERN);
    }

    /**
     * SQL关键字检查，用于检测输入中是否存在潜在的SQL注入风险关键词
     *
     * @param value 待检查的字符串
     * @throws UtilException 当发现SQL关键字时抛出异常
     */
    public static void filterKeyword(String value) {
        // 空值无需检查
        if (StringUtils.isEmpty(value)) {
            return;
        }
        // 分割SQL关键字列表并逐一比对
        String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|");
        for (String sqlKeyword : sqlKeywords) {
            // 忽略大小写匹配关键字
            if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1) {
                throw new UtilException("参数存在SQL注入风险");
            }
        }
    }
}
